using System;
using System.Collections.Generic;
using System.ComponentModel;

using System.Drawing;
using System.Text;
using System.Windows.Forms;
using CodePlex.SpaceBlock;
using System.Diagnostics;
using CodePlex.SpaceBlock.FS;
using CodePlex.Resourceful;

namespace CodePlex.SpaceBlock.UI.Controls
{
    public partial class BrowserControl : CodePlex.SpaceBlock.UI.Controls.BaseControl
    {
        private static class Actions
        {
            public static readonly string Refresh = "Refresh";
            public static readonly string NewFolder = "NewFolder";
            public static readonly string Delete = "Delete";
            public static readonly string Transfer = "Transfer";
            public static readonly string EditACL = "EditACL";
            public static readonly string Properties = "Properties";
            public static readonly string GenerateSignedUrl = "GenerateSignedUrl";
            public static readonly string EditServerAccessLogging = "EditServerAccessLogging";
        }


        private static PropertiesForm _propertiesForm;

        private static PropertiesForm PropertiesForm
        {
            get
            {
                return _propertiesForm;
            }
        }

  
        public event EventHandler TransferFromRequested;
        public event EventHandler TransferToRequested;
        public event EventHandler SelectedPathsChanged;

        private IFileSystem _fileSystem;
        private FoldersControl _folders;
        private FilesControl2 _files;
        private Control _currentFocus;
        private readonly ActionManager _actions;


        public BrowserControl()
        {
            InitializeComponent();

            _actions = new ActionManager(this, UIManager.Instance.SmallImageList, _contextMenu, _toolbar);

            _propertiesForm = new PropertiesForm(_actions);
           

            _folders = new FoldersControl();

            _currentFocus = _folders;   // default to ui default

            _folders.Dock = DockStyle.Fill;

            _splitContainer.Panel1.Controls.Add(_folders);

            _files = new FilesControl2();


            EventHandler bubbleTransferToRequested = delegate
            {
                this.OnTransferToRequested();
            };

            _files.TransferToRequested += bubbleTransferToRequested;

            _folders.TransferToRequested += bubbleTransferToRequested;

            _files.Dock = DockStyle.Fill;

            _splitContainer.Panel2.Controls.Add(_files);


            _fsPicker.DropDownItemClicked += delegate(object sender, ToolStripItemClickedEventArgs e)
            {
                this.SelectFileSystem(e.ClickedItem.Tag as IFileSystem);
            };
        }


        public void Initialize(FileSystemManager manager, int preferredFileSystem)
        {
            _fsPicker.DropDownItems.Clear();
            _fsPicker.AutoSize = true;

            foreach (IFileSystem system in manager.FileSystems)
            {
                
                ToolStripMenuItem item = new ToolStripMenuItem();

                item.Text = system.ShortCaption;
                item.ToolTipText = system.Caption;
                item.Tag = system;

                if (system is LocalFileSystem)
                {
                    item.Image = UIManager.Instance.GetSmallImage("Drive");
                }
                if (system is S3FileSystem)
                {
                    item.Image = UIManager.Instance.GetSmallImage("S3");
                }

                _fsPicker.DropDownItems.Add(item);


            }

            if (preferredFileSystem < 0)
            {
                preferredFileSystem = 0;
            }
            if (preferredFileSystem >= manager.FileSystems.Count)
            {
                preferredFileSystem = manager.FileSystems.Count - 1;
            }

            this.SelectFileSystem(manager.FileSystems[preferredFileSystem]);
        }



        public IFileSystem FileSystem
        {
            get
            {
                return _fileSystem;
            }
        }

        public Path SelectedFolder
        {
            get
            {
                Path rt = null;

                this.InDisplay(delegate {
                    rt =  _folders.SelectedFolder;
                });
                return rt;
            }
            set
            {
                this.FindForm().Cursor = Cursors.WaitCursor;


                this.InBackground(delegate
                {
                    this.InDisplay(delegate
                    {
                        if (value != null)
                        {
                            _folders.SelectedFolder = value;
                        }
                    });
                },delegate
                {
                    this.InDisplay(delegate
                    {
                        this.FindForm().Cursor = Cursors.Default;
                    });

                });
              
            }
        }

        public List<Path> SelectedPaths
        {
            get
            {
                if (_currentFocus == _files)
                {
                    return _files.SelectedFiles;
                }

                List<Path> rt = new List<Path>();
                if (_currentFocus == _folders)
                {
                    if (_folders.SelectedFolder != null)
                    {
                        rt.Add(_folders.SelectedFolder);
                    }
                }
                return rt;
            }
        }






        private void SelectFileSystem(IFileSystem fileSystem)
        {
            if (fileSystem == _fileSystem)
            {
                return;
            }

            foreach (ToolStripMenuItem item in _fsPicker.DropDownItems)
            {
                if (item.Tag == fileSystem)
                {
                    _fsPicker.Image = item.Image;
                    _fsPicker.Text = item.Text;
                    _fsPicker.Width = item.Width;
                    this.Select(fileSystem);
                    return;
                }
            }

        }

        private void Select(IFileSystem fileSystem)
        {
            _fileSystem = fileSystem;
            _folders.Initialize(this.FileSystem);
            _files.Initialize(_actions, this.FileSystem);
            _folders.Select();
            _folders.SelectedFolder = Path.Root;
        }

        private void SyncActions()
        {
           
            if (_currentFocus == _folders)
            {
                if (_folders.SelectedFolder == null)
                {
                    return;
                }
                _actions.SetEnabled(Actions.NewFolder,
                 (this.FileSystem is LocalFileSystem && _folders.SelectedFolder.Level > 0) || (this.FileSystem is S3FileSystem && _folders.SelectedFolder.Level >= 0));
                _actions.SetEnabled(Actions.Delete,
                 (this.FileSystem is LocalFileSystem && _folders.SelectedFolder.Level > 1) || (this.FileSystem is S3FileSystem && _folders.SelectedFolder.Level > 0));
                _actions.SetEnabled(Actions.Transfer,
                 (this.FileSystem is LocalFileSystem && _folders.SelectedFolder.Level > 1) || (this.FileSystem is S3FileSystem && _folders.SelectedFolder.Level > 0));
                _actions.SetEnabled(Actions.EditACL,
               ((this.FileSystem is S3FileSystem) && (_folders.SelectedFolder.Level > 0)));


                _actions.SetEnabled(Actions.Properties, true);
                _actions.SetEnabled(Actions.GenerateSignedUrl, false);
                _actions.SetEnabled(Actions.EditServerAccessLogging, (this.FileSystem is S3FileSystem) && _folders.SelectedFolder.Level == 1);

            }

            else if (_currentFocus == _files)
            {
                _actions.SetEnabled(Actions.Delete, _files.SelectedFiles.Count > 0);
                _actions.SetEnabled(Actions.Transfer, _files.SelectedFiles.Count > 0);
                _actions.SetEnabled(Actions.EditACL, (this.FileSystem is S3FileSystem) && _files.SelectedFiles.Count > 0);

                _actions.SetEnabled(Actions.Properties, _files.SelectedFiles.Count == 1);
                _actions.SetEnabled(Actions.GenerateSignedUrl, (this.FileSystem is S3FileSystem) && _files.SelectedFiles.Count == 1);
                _actions.SetEnabled(Actions.EditServerAccessLogging, false);
            }
           
            this.OnSelectedPathsChanged();
        }


        private void BrowserControl_Load(object sender, EventArgs e)
        {

            _actions.Synchronizing += delegate(object sender2,CancelEventArgs e2)
            {
                Control c = ((ContextMenuStrip)sender2).SourceControl as Control;

                if (!(c is FilesControl2) && !(c is FoldersControl)) 
                {
                    return;
                }
                foreach (string action in _actions.Actions)
                {
                    if (action == Actions.EditServerAccessLogging)
                    {
                        _actions.SetVisible(Actions.EditServerAccessLogging, this.FileSystem is S3FileSystem);
                        _actions.SetVisible(Actions.GenerateSignedUrl, this.FileSystem is S3FileSystem);
                    }
                    else
                    {
                        _actions.SetVisible(action, true);
                    }
                }
            };

          

            _folders.FolderChanged += delegate(object sender2, EventArgs args)
            {
                _files.SelectedFolder = _folders.SelectedFolder;
                this.SyncActions();
            };


            _files.SelectedFilesChanged += delegate
            {
                this.SyncActions();
            };



            _folders.Enter += delegate
            {
                _currentFocus = _folders;
                this.SyncActions();
            };
            _files.Enter += delegate
            {
                _currentFocus = _files;
                this.SyncActions();
            };

            this.SelectedPathsChanged += delegate
            {
                PropertiesForm.Initialize(this.FileSystem, this.SelectedPaths);
            };
         



            // new folder
            _actions.NewAction(Actions.NewFolder, "&New Folder...", UIManager.Instance.GetSmallImageListIndex("NewFolder"), Keys.Control | Keys.N, delegate
             {

                 Control custom = null;

                 S3FileSystem s3fs = this.FileSystem as S3FileSystem;
                 string title = Properties.Messages.NewFolder_Title;
                 string description = Properties.Messages.NewFolder_Description;
                 if (s3fs != null && _folders.SelectedFolder.Level == 0)
                 {
                     NewBucketControl nbc = new NewBucketControl();
                     nbc.Initialize(s3fs.S3Connection);
                     custom = nbc;
                     title = Properties.Messages.NewBucket_Title;
                     description = Properties.Messages.NewBucket_Description;
                 }
                 
                 //this.Select(true, true);
                 string newFolderName = this.Inputbox(
                     _actions.GetIcon("NewFolder"),
                     title,
                     description,
                     "Name:",
                     false,
                     custom);

                 if (newFolderName != null)
                 {
                     try
                     {
                         Path newFolder = _folders.SelectedFolder.Combine(newFolderName + Path.SeparatorChar);

                         NewBucketControl nbc = custom as NewBucketControl;
                         if (nbc != null)
                         {
                             s3fs.S3Connection.CreateBucket(newFolderName, nbc.SelectedDatacenter);
                         }
                         else
                         {
                             this.FileSystem.EnsureFolderExists(newFolder);
                         }
                         _folders.SelectedFolder = newFolder;

                     }
                     catch (Exception ex)
                     {
                         this.HandleException(ex);
                     }


                 }
             });


            // delete
            _actions.NewAction(Actions.Delete, "&Delete...", UIManager.Instance.GetSmallImageListIndex("Delete"), Keys.Delete, delegate
           {

               //this.Select(true, true);

               if (_currentFocus == _folders)
               {


                   Path selectedFolder = _folders.SelectedFolder;

                   if (this.YesNo(UIManager.Instance.GetIcon("Question"),
                       Properties.Messages.DeleteFolder_Title,
                       string.Format(Properties.Messages.DeleteFolder_Description, selectedFolder.Name)))
                   {
                       this.FileSystem.Delete(selectedFolder);

                       _actions.Run(Actions.Refresh);
                   }
               }

               if (_currentFocus == _files)
               {

                   List<Path> selectedFiles = _files.SelectedFiles;

                   string title = Properties.Messages.DeleteFiles_Title;
                   string description = Properties.Messages.DeleteFiles_Description;

                   if (selectedFiles.Count == 1)
                   {
                       title = Properties.Messages.DeleteFile_Title;
                       description = string.Format(Properties.Messages.DeleteFile_Description, selectedFiles[0].Name);
                   }

                   if (this.YesNo(UIManager.Instance.GetIcon("Question"), title, description))
                   {
                       foreach (Path path in selectedFiles)
                       {
                           this.FileSystem.Delete(path);
                       }

                       _actions.Run(Actions.Refresh);

                   }
               }

           });



            // refresh
            _actions.NewAction(Actions.Refresh, "&Refresh...", UIManager.Instance.GetSmallImageListIndex("Refresh"), Keys.F5, delegate
            {
                if (_folders.SelectedFolder != null)
                {
                    _folders.SelectedFolder = _folders.SelectedFolder;
                }
            });


            // transfer
            _actions.NewAction(Actions.Transfer, "&Transfer...", UIManager.Instance.GetSmallImageListIndex("Transfer"), Keys.Control | Keys.T, delegate
            {
                this.OnTransferFromRequested();
            });


            // edit acl
            _actions.NewAction(Actions.EditACL, "&Edit ACL...", UIManager.Instance.GetSmallImageListIndex("EditACL"), Keys.Control | Keys.E, delegate
            {
                ACLEditorForm form = new ACLEditorForm(this.FileSystem, this.SelectedPaths);

                form.Icon = UIManager.Instance.GetIcon("EditACL");
                form.StartPosition = FormStartPosition.CenterScreen;

                form.FormClosed += delegate 
                {
                    if (form.DialogResult == DialogResult.OK)
                    {
                        _actions.Run(Actions.Refresh);
                    }

                    this.FindForm().Activate();
                };

                if (!form.IsDisposed)
                {
                    form.ShowDialog(this);
                }

            });



            // properties
            _actions.NewAction(Actions.Properties, "&Properties", UIManager.Instance.GetSmallImageListIndex("Properties"), Keys.Control | Keys.P, delegate
            {
               // this.Select(true, true);

                if (!PropertiesForm.Visible)
                {
                    PropertiesForm.Show(this);
                }

                PropertiesForm.Activate();

            });


            // generate signed url
            _actions.NewAction(Actions.GenerateSignedUrl, "&Generate Signed Url", UIManager.Instance.GetSmallImageListIndex("Url"), Keys.Control | Keys.G, delegate
            {

                GenerateSignedUrlForm dialog = new GenerateSignedUrlForm();
                dialog.Initialize(this.FileSystem as S3FileSystem, _files.SelectedFiles[0]);


                dialog.Icon = UIManager.Instance.GetIcon("Url");
                dialog.StartPosition = FormStartPosition.CenterScreen;


                dialog.ShowDialog(this);

            });


            // server access logging
            _actions.NewAction(Actions.EditServerAccessLogging, "Edit &Server Access Logging", UIManager.Instance.GetSmallImageListIndex("EditLog"), Keys.Control | Keys.S, delegate
            {
                
                ServerAccessLoggingEditorForm dialog = new ServerAccessLoggingEditorForm();
                dialog.Initialize(this.FileSystem as S3FileSystem, this.SelectedFolder.Name);

                dialog.Icon = UIManager.Instance.GetIcon("EditLog");
                dialog.StartPosition = FormStartPosition.CenterScreen;

                
                dialog.ShowDialog(this);

            });

          
            _actions.BindTo(_folders);
            _actions.BindTo(_files);


            this.SyncActions();
         
        }

     






        private void OnTransferFromRequested()
        {
            if (this.TransferFromRequested != null)
            {
                this.TransferFromRequested(this, EventArgs.Empty);
            }
        }

        private void OnTransferToRequested()
        {
            if (this.TransferToRequested != null)
            {
                this.TransferToRequested(this, EventArgs.Empty);
            }
        }

        private void OnSelectedPathsChanged()
        {
            if (this.SelectedPathsChanged != null)
            {
                this.SelectedPathsChanged(this, EventArgs.Empty);
            }
        }


       

    }
}

